class Fish {
  swim() {
    console.log('fish is swimming!');
  }

  eat() {
    console.log('fish is eating!');
  }
}

class Bird {
  fly() {
    console.log('bird is flying!');
  }

  eat() {
    console.log('bird is eating!');
  }
}

function generalAnimal(type: number): Fish | Bird {
  switch (type) {
    case 1:
      return new Fish();
    case 2:
      return new Bird();
    default:
      throw Error(`Expected Fish or Bird,but got ${type}`);
  }
}

const animal = generalAnimal(1);
animal.eat();
// 使用类型断言
if ((<Fish>animal).swim) {
  (<Fish>animal).swim();
} else if ((<Bird>animal).fly) {
  (<Bird>animal).fly();
}
// 用户自定义的类型保护
function isFish(animal: Fish | Bird): animal is Fish {
  return (<Fish>animal).swim !== undefined;
}

if (isFish(animal)) {
  animal.swim();
} else {
  animal.fly();
}

/**
 * instance类型保护
 */
function getAnimalType(animal: Fish | Bird) {
  if (animal instanceof Fish) {
    return 'this is fish!';
  }
  if (animal instanceof Bird) {
    return 'this is bird!';
  }
  throw Error(`Expected Fish or Bird,but got ${animal}`);
}
console.log(getAnimalType(animal));

/**
 * typeof类型保护
 */
function padLeft(value: string, padding: string | number) {
  if (typeof padding === 'number') {
    return Array(padding + 1).join(' ') + value;
  }
  if (typeof padding === 'string') {
    return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}
console.log(padLeft('welcome to zoo!', 10));
console.log(padLeft('welcome to zoo!', '10'));

// let s = 'foo';
// s = null;
// console.log(s);
